import { nextTick } from 'vue';

// 错误信息接口
export interface ErrorInfo {
  message: string;
  stack?: string;
  componentStack?: string;
  timestamp: number;
  type: string;
  url?: string;
  line?: number;
  column?: number;
  userAgent?: string;
  userId?: string;
  routePath?: string;
}

// 错误处理器类
class ErrorHandler {
  private errorQueue: ErrorInfo[] = [];
  private isShowingError = false;
  private maxErrors = 10; // 最大错误数量限制
  private errorCallbacks: ((errorInfo: ErrorInfo) => void)[] = [];
  private isProcessing = false; // 防止递归错误处理

  // 注册错误显示回调
  public onError(callback: (errorInfo: ErrorInfo) => void) {
    this.errorCallbacks.push(callback);
  }

  // 移除错误显示回调
  public offError(callback: (errorInfo: ErrorInfo) => void) {
    const index = this.errorCallbacks.indexOf(callback);
    if (index > -1) {
      this.errorCallbacks.splice(index, 1);
    }
  }

  // 捕获并处理错误
  public captureError(
    error: Error | string,
    type = 'JavaScript Error',
    extra: Partial<ErrorInfo> = {},
  ) {
    // 防止在错误处理过程中产生新的错误导致无限递归
    if (this.isProcessing) {
      console.warn('Error handler is already processing, skipping:', error);
      return null;
    }

    this.isProcessing = true;

    try {
      const errorInfo: ErrorInfo = {
        message: typeof error === 'string' ? error : error.message,
        stack: typeof error === 'object' ? error.stack : undefined,
        timestamp: Date.now(),
        type,
        userAgent: navigator.userAgent,
        routePath: window.location.pathname,

        ...extra,
      };

      // 添加到错误队列
      this.addToQueue(errorInfo);

      // 显示错误（如果当前没有显示其他错误）
      if (!this.isShowingError) {
        this.showError(errorInfo);
      }

      // 记录到控制台
      this.logError(errorInfo);

      return errorInfo;
    } catch (processingError) {
      // 如果错误处理本身出错，只在控制台记录，不进入处理流程
      console.error('Error in error handler:', processingError);
      return null;
    } finally {
      this.isProcessing = false;
    }
  }

  // 显示错误
  private showError(errorInfo: ErrorInfo) {
    // 开发环境下不显示弹窗，只有错误球
    if (import.meta.env.DEV) {
      this.isShowingError = false;
      return;
    }

    this.isShowingError = true;

    // 触发错误显示回调
    this.errorCallbacks.forEach((callback) => {
      try {
        callback(errorInfo);
      } catch (err) {
        console.error('Error in error callback:', err);
      }
    });
  }

  // 关闭错误显示
  public closeError() {
    this.isShowingError = false;

    // 检查是否有待显示的错误
    nextTick(() => {
      if (this.errorQueue.length > 0 && !this.isShowingError) {
        const nextError = this.errorQueue.shift();
        if (nextError) {
          this.showError(nextError);
        }
      }
    });
  }

  // 添加到错误队列
  private addToQueue(errorInfo: ErrorInfo) {
    // 避免重复错误
    const isDuplicate = this.errorQueue.some(
      (existing) =>
        existing.message === errorInfo.message &&
        existing.type === errorInfo.type &&
        errorInfo.timestamp - existing.timestamp < 5000, // 5秒内相同错误视为重复
    );

    if (!isDuplicate) {
      this.errorQueue.push(errorInfo);

      // 限制队列长度
      if (this.errorQueue.length > this.maxErrors) {
        this.errorQueue.shift();
      }
    }
  }

  // 记录错误到控制台
  private logError(errorInfo: ErrorInfo) {
    console.group(`🚨 ${errorInfo.type} - ${new Date(errorInfo.timestamp).toLocaleTimeString()}`);
    console.error('Message:', errorInfo.message);

    if (errorInfo.stack) {
      console.error('Stack:', errorInfo.stack);
    }

    if (errorInfo.componentStack) {
      console.error('Component Stack:', errorInfo.componentStack);
    }

    console.error('Full Info:', errorInfo);
    console.groupEnd();
  }

  // 获取错误队列
  public getErrorQueue(): ErrorInfo[] {
    try {
      return [...this.errorQueue];
    } catch (error) {
      console.error('Error getting error queue:', error);
      return [];
    }
  }

  // 清空错误队列
  public clearErrorQueue() {
    try {
      this.errorQueue.length = 0; // 更安全的清空方式
    } catch (error) {
      console.error('Error clearing error queue:', error);
      // 降级方案
      this.errorQueue = [];
    }
  }

  // 设置用户信息（用于错误追踪）
  public setUser(userId: string) {
    this.errorCallbacks.forEach((callback) => {
      // 这里可以扩展用户信息设置逻辑
    });
  }
}

// 创建全局错误处理器实例
export const globalErrorHandler = new ErrorHandler();

// Vue 错误处理器
export const vueErrorHandler = (err: any, instance: any, info: string) => {
  const componentName =
    instance?.$options?.name || instance?.$options?.__name || 'Unknown Component';

  globalErrorHandler.captureError(err, 'Vue Component Error', {
    componentStack: `${info} in <${componentName}>`,
  });
};

// 全局未捕获错误处理器
export const globalUncaughtErrorHandler = (event: ErrorEvent) => {
  globalErrorHandler.captureError(event.error || event.message, 'Uncaught Error', {
    url: event.filename,
    line: event.lineno,
    column: event.colno,
  });
};

// 未处理的 Promise 拒绝处理器
export const unhandledRejectionHandler = (event: PromiseRejectionEvent) => {
  const error = event.reason;

  globalErrorHandler.captureError(
    error instanceof Error ? error : String(error),
    'Unhandled Promise Rejection',
  );

  // 防止在控制台显示未处理的 Promise 拒绝警告
  event.preventDefault();
};

// 资源加载错误处理器
export const resourceErrorHandler = (event: Event) => {
  const target = event.target as HTMLElement;
  const tagName = target.tagName.toLowerCase();
  const src = (target as any).src || (target as any).href;

  globalErrorHandler.captureError(`Failed to load ${tagName}: ${src}`, 'Resource Load Error', {
    url: src,
  });
};

// 网络错误处理器
export const networkErrorHandler = (error: any, url?: string, method?: string) => {
  globalErrorHandler.captureError(error, 'Network Error', {
    url,
    // 可以添加更多网络相关信息
    ...(method && { method }),
  });
};

// 初始化全局错误处理
export const initGlobalErrorHandling = () => {
  // 监听全局未捕获错误
  window.addEventListener('error', globalUncaughtErrorHandler);

  // 监听未处理的 Promise 拒绝
  window.addEventListener('unhandledrejection', unhandledRejectionHandler);

  // 监听资源加载错误
  window.addEventListener('error', resourceErrorHandler, true);

  // 当页面卸载时清理
  window.addEventListener('beforeunload', () => {
    window.removeEventListener('error', globalUncaughtErrorHandler);
    window.removeEventListener('unhandledrejection', unhandledRejectionHandler);
    window.removeEventListener('error', resourceErrorHandler, true);
  });
};

// 手动触发错误（用于测试）
export const triggerTestError = (type: 'js' | 'vue' | 'promise' | 'network' = 'js') => {
  switch (type) {
    case 'js':
      throw new Error('这是一个测试 JavaScript 错误');

    case 'vue':
      // 这需要在 Vue 组件中调用
      console.warn('请在 Vue 组件中调用此测试');
      break;

    case 'promise':
      Promise.reject(new Error('这是一个测试 Promise 拒绝错误'));
      break;

    case 'network':
      globalErrorHandler.captureError('网络请求失败', 'Network Error', {
        url: '/api/test-error',
      });
      break;
  }
};

export default globalErrorHandler;
